文章目录
  1. 1. JSP中的标签库
    1. 1.1. 标签库运行原理
    2. 1.2. 自定义标签库
    3. 1.3. 标签库的uri路径引入
    4. 1.4. 补充

JSP中的标签库

标签库运行原理

​ JSP标签的定义步骤:

​ 1 创建标记处理类( 处理标签的类必须扩展javax.servlet.jsp.TagSupport 或 BodyTagSupport)

​ 2 创建TLD文件

​ 3 在jsp页面通过指令引入标签库

自定义标签库

​ 创建标记处理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package test; 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class OutputTag extends TagSupport {
private String name=null;
public void setName(String name) {
this.name = name;
}
public int doEndTag() throws JspException
{
try {
JspWriter out = pageContext.getOut();
out.print("Hello! " + name);
  } catch (Exception e) { throw new JspException(e); }
return EVAL_PAGE;
}
}

1 如何输出到jsp页面:调用JspWriter JspWriter out = pageContext.getOut();out.print……记住这个方法就可以了。
2 输出后如何作处理,函数会返回几个值之一。EVAL_PAGE 表示tag已处理完毕,返回jsp页面。还有几个值,例如 EVAL_BODY_AGAIN 和EVAL_BODY_INCLUDE等 跟流程控制有关.

Tag系列的Interface里定义的静态int,通过他们也能一窥tag组键的执行流程,这几个静态值分别是:
SKIP_BODY : 跳过了开始和结束标签之间的代码,一般是在doStartTag中使用
EVAL_BODY_INCLUDE :处理嵌套的标签,一般是在doStartTag中使用,由负责处理标签正文的tag接口提供
EVAL_BODY_BUFFERED :对包含的内容进行解析 一般是在doStartTag中使用,由负责处理标签正文的bodyTag接口提供,目的是通知jsp容器作好读取正文的工作(创建一个body-content包装正文和获取存放操作结果的out对象,便于以后的操作和输出).
EVAL_BODY_AGAIN:处理标签正文,嵌套标签的iteratorTag接口的使用
SKIP_PAGE : 忽略剩下的页面,一般是在doEndTag中使用
EVAL_PAGE : 继续执行下面的页, 一般是在doEndTag中使用

编写tld 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="ISO-8859-1" ?> 
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>test</short-name>
<!--OutputTag-->
<tag>
<name>out</name>
<!-- 全限定路径 -->
<tag-class>test.OutputTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>

在WEB-INF下新建tlds文件夹,把这个文件取名为test.tld,放到tlds文件夹下。引用时的路径应该这样:WEB-INF\tlds\test.tld

关于tld的简单说明:
short-name:taglib的名称,也称为前缀。比如“c:out value=””/” 里的“c”
name:tag的名字。例如“c:out value=””/” 里的”out”,我们的类也取名为out,由于有前缀作区分,不会同其他库的 同名tag组件混淆
tag-class:完整的tag组件路径,记着带包名
body-content:指tag之间的内容。例如c:out value=”” …… /c 起始和关闭标签之间就是body-content。由于没有处理body-content ,所以上面设为empty,如果是嵌套标签,或则是要在服务器端处理标签体的话,就是jsp了
“attribute”里的name:属性名字。例如c:out value=””/里的value。名字可任意取,只要类里提供相应的set方法即 可。
required:是否必填属性。
rtexprvalue:是否支持运行时表达式取值就是是否可以<%=%>或则是${}方式传值。
这是tag的强大功能。

编写jsp

1
2
3
4
5
6
7
<%@ page language="java"%> 
<%@ taglib uri="/WEB-INF/tlds/test.tld" prefix="test"%>
<html>
<body>
Test Tag: <test:out name="TEST"/>
</body>
</html>

标签库的uri路径引入

​ 在JSP中使用标签是很平常的事情,在制作自定义标签时,通常都需要写tld文件来定义标签的各种属性,对应的java类,前缀等等。标签与tld文件紧紧相连,那么,到底应该怎么放置tld文件?在web.xml中怎么定义tld文件的位置?

​ Web容器(jsp引擎)遇到类似【<c:import】这样的标签时,会通过prefix定位到uri,再根据uri定位到相应的tld文件,对tld文件进行解析。其中uri ——–tld文件的映射关系如下:

Key (Uri) Value(String[] taglib_tld_location)

​ /jstl-examples-taglib、 taglib_tld_location[0] + taglib_tld_location[1]

http://java.sun.com/jstl/core

Tld文件路径定义方式

​ 如下方式1和方式2只能在2.3版本使用,Servlet2.4开始便不能在web.xml中定义taglib了。

​ <!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

​ “http://java.sun.com/dtd/web-app_2_3.dtd">

l 方式1

​ 如下所示,在web.xml中定义

1
2
3
4
 <taglib>
<taglib-uri>/jstl-examples-taglib</taglib-uri>
<taglib-location>/WEB-INF/lib/jstl-examples.tld</taglib-location>
</taglib>

如果这样定义的话,映射关系便如下:

/jstl-examples-taglib —————-{“/WEB-INF/lib/jstl-examples.tld”,””} // taglib_tld_location[0]就足以表示tld路径,因此taglib_tld_location[1]为空。

方式二:

​ 如下所示,在web.xml中定义

1
2
3
4
 <taglib>
<taglib-uri>/jstl-examples-taglib</taglib-uri>
<taglib-location>/WEB-INF/lib/jstl-examples.jar</taglib-location>
</taglib>

如果这样定义的话,映射关系便如下:

/jstl-examples-taglib ———– {“/WEB-INF/lib/ jstl-examples.jar”,” META-INF/taglib.tld”}

// taglib_tld_location[0]表示jar路径,taglib_tld_location[1]固定为META-INF/taglib.tld(也就是说,tld在jar文件中的保存路径必须是META-INF/taglib.tld,名称必须是taglib.tld)。这就是说一个jar里只能有一个tld。如果代码中不固定为taglib.tld的话,也很难处理,因为如果tld的名称可以随便定义的话,出现多个tld在jar文件中时将会导致混乱。

方式三:

不需要在web.xml中定义,只需要把tld保存在web应用能够使用的jar文件中的META-INF路径下便可。这种情况的机制是这样的:web容器会遍历当前web应用能够访问的jar文件,从jar文件中查找META-INF/xxx.tld文件,当找到一个tld文件之后,便会解析tld文件,取出节点的值,把uri作为key值生成映射关系。

如下所示的jstl的core标签库的tld文件,便会有如下的映射关系

http://java.sun.com/jstl/core ——–{“tld文件所在的jar文件的路径”,” META-INF/xxx.tld”}

//taglib_tld_location[0]表示jar路径,taglib_tld_location[1]为所搜到的tld在jar文件中的相对路径

例:这是jstl.jar中的META-INF/c.tld文件的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<description>JSTL 1.1 core library</description>
<display-name>JSTL core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>c</short-name>
<uri>http://java.sun.com/jsp/jstl/core</uri>

<validator>
<description>
Provides core validation features for JSTL tags.
</description>
<validator-class>
org.apache.taglibs.standard.tlv.JstlCoreTLV
</validator-class>
</validator>

<tag>
<description>
Catches any Throwable that occurs in its body and optionally
exposes it.
</description>
<name>catch</name>
<tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>
Name of the exported scoped variable for the
exception thrown from a nested action. The type of the
scoped variable is the type of the exception thrown.
</description>
<name>var</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>

Tld文件的解析逻辑

以jstl为例:

Web容器遇到类似【<c:import】标签时,就会通过在头部中定义的<%@ taglib prefix=”c” uri=”http://java.sun.com/jstl/core" %>找到uri,再根据此uri便可以定位到taglib_tld_location。当taglib_tld_location[0]不是jar文件时,便直接使用java的FileInputStream读取tld文件;当taglib_tld_location[0]是jar文件时,则会

通过如下代码读取tld文件。

URL jarFileUrl = new URL(“jar:” + location[0] + “!/“);

ZipEntry jarEntry = jarFile.getEntry(location[1]);

总结:

​ tld的定义可以不在web.xml中定义,这时需要保证tld在web应用能够访问的jar中,并且保存在jar的META-INF目录下。此时JSP直接使用tld中定义的\<uri>便可;

如果在web.xml中定义tld的路径的话,可以直接指定tld文件路径,此时要保证tld不在jar包中(比如在WEB-INF目录下);也可以指定为jar文件路径,此时要保证tld在jar中且路径为META-INF/taglib.tld。

在web.xml中定义的uri优先级要高于tld文件中定义的优先级。

补充

​ jsp中使用JSTL,需要哪些jar包?

​ jstl.jar和standard.jar

​ standard.jar是JSP标准标签库,和jstl.jar 1.0版本中一起使用,

​ 但在jstl-1.2.jar就不再需要了

参考: JSP标签在tomcat中的运行原理 https://www.iteye.com/blog/jianfulove-1826982

​ jsp自定义标签(taglib)编写的原理和实现 https://blog.csdn.net/zhangdaiscott/article/details/8622975

​ 如何引用自定义标签库中的tld文件 http://blog.sina.com.cn/s/blog_7ffe993c01019ebe.html

文章目录
  1. 1. JSP中的标签库
    1. 1.1. 标签库运行原理
    2. 1.2. 自定义标签库
    3. 1.3. 标签库的uri路径引入
    4. 1.4. 补充